<template>
  <!-- label-width="100px"统一设置 label的样式 -->
  <el-form label-width="100px" ref="spuFormRef" :model="spuInfo" :rules="spuRules">
    <!-- 这里添加校验规则,引入三个东西,双向数据绑定,设定的规则,需要校验的数据 -->
    <!-- 然后在需要校验的数据上级的el-form-item中,添加prop,与校验的规则绑定 在需要验证的prop中,添加v-model双向数据绑定 -->
    <el-form-item label="spu名称" prop="spuName">
      <el-input placeholder="SPU名称" v-model="spuInfo.spuName"></el-input>
    </el-form-item>
    <el-form-item label="品牌" prop="tmId">
      <el-select placeholder="请选择品牌" v-model="spuInfo.tmId">
        <el-option v-for="trademark in trademarkList" :label="trademark.tmName" :value="trademark.id" :key="trademark.id" />
      </el-select>
    </el-form-item>
    <el-form-item label="描述" prop="description">
      <el-input type="textarea" :rows="3" v-model="spuInfo.description"></el-input>
    </el-form-item>
    <!-- 上传图片 -->
    <el-form-item label="spu图片" prop="spuImageList">
      <el-upload
        v-model:file-list="spuInfo.spuImageList"
        :action="`${BASE_URL}/admin/product/upload`"
        list-type="picture-card"
        :on-preview="handlePictureCardPreview"
        :on-remove="handleRemove"
        :on-success="handleAvatarSuccess"
        :before-upload="beforeAvatarUpload"
      >
        <el-icon><Plus /></el-icon>
      </el-upload>

      <el-dialog v-model="dialogVisible">
        <img w-full :src="dialogImageUrl" alt="Preview Image" />
      </el-dialog>
    </el-form-item>
    <!-- 销售属性 -->
    <el-form-item label="销售属性" prop="">
      <!-- <el-select v-model="spuInfo.spuSaleAttr" :placeholder="`${filterBaseSaleAttrList.length} ` ? `还有${filterBaseSaleAttrList.length}条数据` : '没有了'"> -->
      <!-- 上面这种情况判断就是判断`${filterBaseSaleAttrList.length} `是否有值,这个数据一直有数字的字符串,一直是true,所以永远走true,需要用如下方法在内部判断 -->
      <el-select v-model="spuInfo.spuSaleAttr" :placeholder="`${filterBaseSaleAttrList.length ? `还有${filterBaseSaleAttrList.length}条数据` : '没有'}`">
        <el-option v-for="baseSaleAttr in filterBaseSaleAttrList" :key="baseSaleAttr.id" :label="baseSaleAttr.name" :value="baseSaleAttr.name" />
      </el-select>
      <el-button :icon="Plus" type="primary" :disabled="!spuInfo.spuSaleAttr" @click="addSpuSaleAttr">添加销售属性</el-button>

      <el-table border :data="spuInfo.spuSaleAttrList" style="margin-top: 20px">
        <el-table-column label="序号" width="80px" type="index" align="center"></el-table-column>
        <el-table-column label="属性名" prop="saleAttrName"></el-table-column>
        <el-table-column label="属性值名称列表">
          <template v-slot="{ row }">
            <el-tag v-for="tag in row.spuSaleAttrValueList" :key="tag" class="mx-1" closable :disable-transitions="false" @close="handleClose(row, tag)">
              {{ tag.saleAttrValueName }}
            </el-tag>
            <el-input v-if="row.inputVisible" ref="InputRef" v-model="inputValue" class="ml-1 w-20" size="small" @keyup.enter="handleInputConfirm(row)" @blur="handleInputConfirm(row)" />
            <el-button v-else class="button-new-tag ml-1" size="small" @click="showInput(row)"> + New Tag </el-button></template
          >
        </el-table-column>
        <el-table-column label="操作">
          <el-popconfirm confirm-button-text="确定" cancel-button-text="取消" :icon="InfoFilled" icon-color="#626AEF" title="真的确定要删除此条数据么?" @confirm="deleteAttr($index)">
            <template #reference>
              <el-button title="删除" type="danger" size="small" :icon="Delete" />
            </template>
          </el-popconfirm>
        </el-table-column>
      </el-table>
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="submitForm(spuFormRef)">保存</el-button>
      <el-button @click="emits('sendShowSpu', 1)">取消</el-button>
    </el-form-item>
  </el-form>
</template>

<script lang="ts">
export default {
  name: "SpuForm",
}
</script>
<script lang="ts" setup>
import { ref, onMounted, reactive, computed, nextTick } from "vue"
import { Plus, Delete, InfoFilled } from "@element-plus/icons-vue"
import { ElMessage } from "element-plus"
import type { UploadProps, UploadFile, UploadFiles, UploadUserFile, ElInput, FormInstance } from "element-plus"
// 引入请求接口函数/
import { reqGetAllTrademarkList, reqGetBaseSaleAttrList, reqGetSpuImageList, reqGetSpuSaleAttrList, reqSaveSpuInfo, reqUpdateSpuInfo } from "@/api/product/spu"
import { useCategoryListStore } from "@/stores/categoryList"
const categoryStore = useCategoryListStore()

// 引入校验
const spuFormRef = ref<FormInstance>()
const formSize = ref("default")
// 添加校验规则
const spuRules = reactive<FormRules>({
  spuName: [
    { required: true, message: "请输入SPU名称", trigger: "blur" },
    // required,是否必填,message提示消息,trigger触发条件
    { min: 1, max: 10, message: "SPU名称在1-10个字符之间", trigger: "blur" },
  ],
  tmId: [{ required: true, message: "请选择SPU品牌", trigger: "change" }],
  description: [{ required: true, message: "请输入SPU描述", trigger: "blur" }],
  spuImageList: [{ required: true, message: "请选择一张图片", type: "array", trigger: "change" }],
  spuSaleAttrList: [{ required: true, message: "请至少添加一个属性", type: "array", trigger: "click" }],
})
// 引入自定义事件
const emits = defineEmits(["sendShowSpu"])

// tag标签组件需要的变量
const inputValue = ref("")
// const dynamicTags = ref(["Tag 1", "Tag 2", "Tag 3"])
const inputVisible = ref(false)
const InputRef = ref<InstanceType<typeof ElInput>>()

// console.log("base", import.meta.env.VITE_API_URL) // 查看全局配置的路径
const BASE_URL = import.meta.env.VITE_API_URL

const fileList = ref<UploadUserFile[]>([])

const dialogImageUrl = ref("")
const dialogVisible = ref(false)

// 准备两个列表数组 trademarkList 品牌数组  baseSaleAttrList基本属性列表
const trademarkList = ref([])
const baseSaleAttrList = ref([])
// 准备接受传递过来的数据
const props = defineProps(["getSpuInfo"])
// 定义一个存储spu相关数据的变量
let spuInfo = reactive({
  spuName: "",
  tmId: "", // spu品牌
  description: "", // spu描述
  spuImageList: [], // 存储spu图片的数组
  spuSaleAttrList: [], // 基本销售属性
  spuSaleAttr: "", // 收集选中的属性
  category3Id: "", // 三级id

  // 将传递过来的属性展开在数据源中.使用es6的语法展开运算符
  ...props.getSpuInfo,
  // 在进行修改操作时发现,还是获取不了属性和图片,需要重新发送请求
})

onMounted(async () => {
  if (spuInfo.id) {
    // 更新操作
    // 这里用到一个promise语法,promise.all([]),发送两个请求,只要一个失败都失败,所以我们需要用一个catch try包裹防止错误
    try {
      const { id } = spuInfo
      // 原来的两个函数
      const [responseTrademarkList, responseBaseSaleAttrList] = await Promise.all([reqGetAllTrademarkList(), reqGetBaseSaleAttrList()])
      // console.log("aa", responseTrademarkList, responseBaseSaleAttrList)
      trademarkList.value = responseTrademarkList
      baseSaleAttrList.value = responseBaseSaleAttrList
      if (id) {
        // 如果id有值，说明此时是编辑操作，需要再加上两个接口函数
        const [responseSpuImageList, responseSpuSaleAttrList] = await Promise.all([reqGetSpuImageList(id), reqGetSpuSaleAttrList(id)])
        // spuInfo.spuImageList = responseSpuImageList
        // 最后发现还是不能显示图片,通过查看插件,发现图片格式与预期不一样,需要添加name,url属性
        console.log(responseSpuImageList)
        if (responseSpuImageList) {
          //  如果拿到响应的数据图片,我们将图片的添加两个属性
          console.log("挂载完成,我只应该打印一次", responseSpuImageList)
          spuInfo.spuSaleAttrList = responseSpuSaleAttrList

          spuInfo.spuImageList = responseSpuImageList.map(item => {
            return {
              ...item, // 原来的ImgName和imgUrl也要
              // 这两行用来渲染页面上的图片需要的格式
              name: item.imgName,
              url: item.imgUrl,
            }
          })
        }
        // spuInfo.id = ""
        // console.log
      }
    } catch (error) {
      ElMessage.error("获取属性失败...")
    }
  } else {
    props.getSpuInfo = ""
  }
})

// 上传图片成功的函数
const handleAvatarSuccess: UploadProps["onSuccess"] = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  console.log("上传成功的", response, uploadFile)
  //   往定义的发送请求的参数中spuImageList数组中,添加需要的图片的信息,
  // spuInfo.spuImageList.push({
  //   // a: "1",
  //   imgName: uploadFile.name,
  //   imgUrl: response.data,
  // })
  // debugger
  spuInfo.spuImageList = uploadFiles //
  console.log(spuInfo.spuImageList)
}
// 弹出框之请求成功前 这个方法一般用来判断图片是否合格---常用来做限定图片的操作
const beforeAvatarUpload: UploadProps["beforeUpload"] = rawFile => {
  const Filetype = ["image/jpeg", "image/jpg", "image/png"]
  // console.log(rawFile)// 图片文件
  //设置一个图片格式白名单
  if (!rawFile.type.includes(rawFile.type)) {
    ElMessage.error("请上传符合要求的图片!")
    return false
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error("图片大小不能超过2M,请重新选择...!")
    return false
  }

  // 清除校验规则
  // 问题,需要在return前写,不然TMD都return了.就不执行下面的代码了
  //   ruleFormRef.value?.clearValidate()
  // 由于图片的特殊性,需要手动清除校验规则
  // 只清除图片的校验规则

  // 这里如果不加!,ts语法会报错,原因是spuFormRef有可能是undefined,我们手动添加一个!,这个符号叫做非空断言操作符
  // 非空断言操作符操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。即： x! 将从 x 值域中排除 null 和 undefined
  spuFormRef.value!.clearValidate(["spuImageList"])

  return true
}
// 删除图片触发函数
const handleRemove: UploadProps["onRemove"] = (uploadFile, uploadFiles) => {
  //   uploadFile删除项, uploadFiles剩下的图片
  //   console.log("remove", uploadFile, uploadFiles)
  spuInfo.spuImageList = uploadFiles //重新赋值
}
// 放大图片的函数
const handlePictureCardPreview: UploadProps["onPreview"] = uploadFile => {
  dialogImageUrl.value = uploadFile.url!
  dialogVisible.value = true
  // console.log(uploadFile.url)
}
// 6. 添加销售属性值
const addSpuSaleAttr = () => {
  // 当用户当前的属性名没有添加属性值时,不能在往下添加别的属性名
  // 所以我们要判断当前所有的属性名中的值是否为空 使用数组的some或者every方法
  const isNullSpuSaleAttrList = spuInfo.spuSaleAttrList
  // 首先还要确认用户已经添加了至少一项,在判断
  if (isNullSpuSaleAttrList.length && !isNullSpuSaleAttrList.some(item => item.spuSaleAttrValueList.length)) {
    // 注意,短路运算需要执行,必须两个条件都满足,需要想办法
    // some有一个返回false就是false
    return ElMessage.warning("有属性值为空.请添加")
  }
  // 在准备发送请求的时候发现这里少了一个参数,baseSaleAttrId,这个参数是销售属性对应的id值,因为服务器端接受不会看到具体的数据,只能通过id来识别对应的数据
  // baseSaleAttrList这个是对应的销售属性的全部值 我们需要在这里找到当前添加的那一项,并且吧这一项的id赋值给对应的那一项
  const id = baseSaleAttrList.value.find(item => item.name == spuInfo.spuSaleAttr).id
  // console.log(id)// 拿到id
  spuInfo.spuSaleAttrList.push({
    // 所以我们需要在这里添加进去
    // 那么再次查看发请求的参数，发现在添加具体的属性值的地方也需要一个id值
    baseSaleAttrId: id,

    // 添加这个属性的原因是,在进行属性值的列表添加修改时,会影响到其他列的数据,使用每列添加独立的属性,点击添加将点击哪项修改为true
    inputVisible: false, // 给当前行的对象添加一个属性,用于控制按钮和输入框的显示

    // 这里的两个参数都是根据接口请求参数定义的,一定要一字不差
    saleAttrName: spuInfo.spuSaleAttr,
    spuSaleAttrValueList: [],
  })

  // 这里如果不加!,ts语法会报错,原因是spuFormRef有可能是undefined,我们手动添加一个!,这个符号叫做非空断言操作符
  // 非空断言操作符操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。即： x! 将从 x 值域中排除 null 和 undefined
  spuFormRef.value!.clearValidate(["spuSaleAttrList"])
  spuInfo.spuSaleAttr = "" // 清空下拉框选项
}
// 7. 使用计算属性 获取剩余的基础销售属性
const filterBaseSaleAttrList = computed(() => {
  return baseSaleAttrList.value.filter(baseSale => {
    return !spuInfo.spuSaleAttrList.find(item => baseSale.name === item.saleAttrName)
  })
})
// 8. 清除当前属性
const deleteAttr = (index: number) => {
  spuInfo.spuSaleAttrList.splice(index, 1)
}
// 删除某一项属性值
const handleClose = (row, tag: string) => {
  //   dynamicTags.value.splice(dynamicTags.value.indexOf(tag), 1)
  //   通过row.spuSaleAttrValueList这个数组使用find方法找到需要删除的那一项的索引,在用splice切割数组的方法进行删除
  row.spuSaleAttrValueList.splice(row.spuSaleAttrValueList.indexOf(tag), 1)
  //   console.log(row.spuSaleAttrValueList)
}
// 点击添加属性值,自动获取焦点
const showInput = row => {
  //   console.log(123)
  row.inputVisible = true
  nextTick(() => {
    InputRef.value!.input!.focus()
  })
}
// 添加具体的属性值tag
const handleInputConfirm = row => {
  if (inputValue.value) {
    // 注意:在添加之前需要判断添加的值与原值是否重复
    if (row.spuSaleAttrValueList.find(item => item.saleAttrValueName === inputValue.value)) {
      // 如果能找到,说明值重复了,不要添加
      // 清空输入框,返回span标签
      row.inputVisible = false // 将输入框隐藏
      inputValue.value = "" // 清空输入框
      // 提示用户
      return ElMessage.warning("添加的值重复,请重试")
    }
    const id = baseSaleAttrList.value.find(item => item.name === row.saleAttrName).id
    row.spuSaleAttrValueList.push({
      baseSaleAttrId: id,
      saleAttrValueName: inputValue.value,
      saleAttrName: row.saleAttrName,
    }) // 添加属性值
  }

  row.inputVisible = false // 将输入框隐藏
  inputValue.value = "" // 清空输入框
}
// 表单提交
const submitForm = async (formEl: FormInstance | undefined) => {
  if (!formEl) return // 不同通过校验,不发送请求
  await formEl.validate(async (valid, fields) => {
    if (valid) {
      // 发送真正的请求前,在判断一下,table表格中的值是否有空值
      const spuSaleAttrList = spuInfo.spuSaleAttrList // table表格中的数据,也就是属性名
      // spuSaleAttrList.map(item => console.log(item.spuSaleAttrValueList))
      if (spuSaleAttrList.length && !spuSaleAttrList.every(item => item.spuSaleAttrValueList.length)) {
        ElMessage.error("有属性值为空，请添加...")
        return // 不要添加了
      }
      // 提取一下图片的内容
      spuInfo.spuImageList = spuInfo.spuImageList.map(item => {
        return {
          imgUrl: item.response?.data || item.url,
          imgName: item.name,
        }
      })
      spuInfo.category3Id = categoryStore.category3Id // 还需要一个3id
      emits("sendShowSpu", 1)
      spuInfo.category3Id = categoryStore.category3Id
      if (spuInfo.id) {
        // 此时是更新操作
        await reqUpdateSpuInfo(spuInfo)
      } else {
        // 才是真正的添加spuInfo
        await reqSaveSpuInfo(spuInfo)
      }
    } else {
      console.log("error submit!", fields)
    }
  })
}
</script>

<style></style>
